package abg.core.common.security;

import abg.core.common.cache.Cache;
import abg.core.common.util.coll.ArrayKit;
import abg.core.domain.sys.MSG;
import abg.core.domain.sys.ServiceException;
import com.alibaba.fastjson2.JSONObject;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 表参参数重复提交校验
 */
@Aspect
@Component
@Slf4j
public class ReSubmitHandler {
    @Resource
    private Cache<String> cache;

    @Resource
    private Redisson redisson;


    @Around(value = "@annotation(reSubmit)")
    public Object handlerReSubmit(ProceedingJoinPoint joinPoint, ReSubmit reSubmit) throws Throwable {
        Object response;

        //针对一个KEY进行加锁（默认超时时间30秒）
        String validKEY = createValidKEY(reSubmit);
        RLock lock = redisson.getLock(validKEY);
        try {
            lock.lock();
            response = joinPoint.proceed();
        } finally {
            lock.unlock();
        }
        return response;
    }

    /**
     * 生成唯一请求标记
     *
     * @return 唯一请求标记
     */
    private String createValidKEY(ReSubmit reSubmit) {
        boolean hasLogin = reSubmit.hasLogin();
        List<String> lockKeyList = ArrayKit.asList(reSubmit.value());
        long expire = reSubmit.expire();


        StringBuilder builderKey = new StringBuilder();
        //必须登录后使用
        if (hasLogin) {
            AuthUser authUser = AuthKit.mastLogin();
            builderKey.append(authUser.getUserId());
        }

        //追加请求地址和请求参数
        HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
        String requestURI = request.getRequestURI();
        builderKey.append(requestURI);
        if (!request.getParameterMap().isEmpty()) {
            Map<String, String[]> parameterMap = request.getParameterMap();
            if (lockKeyList.size() == 0) {
                builderKey.append(JSONObject.toJSONString(parameterMap));
            } else {
                for (String lockKey : lockKeyList) {
                    String[] lockKeyValue = parameterMap.get(lockKey);
                    if (lockKeyValue == null || lockKeyValue.length == 0) {
                        log.error("加锁参数为空 key=" + lockKey + "; parameterMap=" + JSONObject.toJSONString(parameterMap));
                        throw new ServiceException(MSG.PARAM_ER);
                    }
                    builderKey.append(JSONObject.toJSONString(lockKeyValue));
                }
            }
        }

        //返回KEY标记
        return builderKey.toString();
    }


}
